package com.dews.warn.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dews.common.core.domain.model.LoginUser;
import com.dews.common.exception.ServiceException;
import com.dews.common.utils.SecurityUtils;
import com.dews.course.domain.entity.StudentScore;
import com.dews.course.enums.SemesterEnum;
import com.dews.course.service.IStudentScoreService;
import com.dews.information.domain.entity.StudentInfo;
import com.dews.information.service.IStudentInfoService;
import com.dews.train.domain.entity.ProgramTeachPlan;
import com.dews.train.domain.entity.TrainingProgram;
import com.dews.train.enums.StudyRequireEnum;
import com.dews.train.service.IProgramTeachPlanService;
import com.dews.train.service.ITrainingProgramService;
import com.dews.warn.domain.ro.StuCreditRo;
import com.dews.warn.service.DataStatisticsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.AbstractMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author 清风学Java
 * @version 1.0.0
 * @date 2025/2/6
 */
@Service
public class DataStatisticsServiceImpl implements DataStatisticsService {

    private ITrainingProgramService trainingProgramService;
    private IProgramTeachPlanService programTeachPlanService;
    private IStudentInfoService studentInfoService;
    private IStudentScoreService studentScoreService;

    @Autowired
    public DataStatisticsServiceImpl(ITrainingProgramService trainingProgramService,
                                     IProgramTeachPlanService programTeachPlanService,
                                     IStudentInfoService studentInfoService,
                                     IStudentScoreService studentScoreService) {
        this.trainingProgramService = trainingProgramService;
        this.programTeachPlanService = programTeachPlanService;
        this.studentInfoService = studentInfoService;
        this.studentScoreService = studentScoreService;
    }

    /**
     * 统计学生每学期学分修读情况
     *
     * @return
     */
    @Override
    public StuCreditRo statisticsDegreeGrade() {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (ObjectUtil.isEmpty(loginUser)) {
            throw new ServiceException("当前用户不存在，无法统计学生每学期学分修读情况！");
        }
        StudentInfo studentInfo = studentInfoService.getOne(Wrappers.lambdaQuery(StudentInfo.class).eq(StudentInfo::getUserId, loginUser.getUserId()));
        // 查询学生成绩信息
        List<StudentScore> studentScoreList = studentScoreService.list(
                Wrappers.lambdaQuery(StudentScore.class)
                        .eq(StudentScore::getUserId, loginUser.getUserId())
        );
        Map<String, Double> stuScoreMap = studentScoreList.stream()
                .collect(Collectors.toMap(
                        StudentScore::getSemester,
                        score -> score.getCredits() != null ? score.getCredits() : 0.0,
                        Double::sum
                ));
        // 按学制判断学期数
        List<SemesterEnum> semesterEnumList = SemesterEnum.getSemesterEnumList(studentInfo.getEducationalSystem());
        // 查询这个学生下的人才培养方案
        TrainingProgram trainingProgram = trainingProgramService.getOne(
                Wrappers.lambdaQuery(TrainingProgram.class)
                        .eq(TrainingProgram::getDepId, studentInfo.getDepId())
                        .eq(TrainingProgram::getSubjectId, studentInfo.getSubjectId())
                        .eq(TrainingProgram::getGrade, studentInfo.getGrade())
                        .eq(TrainingProgram::getIsEnable, 1)
        );
        AtomicReference<Map<Integer, Double>> teachPlanMap = new AtomicReference<>(Collections.emptyMap());
        Optional.ofNullable(trainingProgram)
                .ifPresent(t -> {
                    // 查询人才培养方案下的教学计划
                    teachPlanMap.set(
                            programTeachPlanService.list(
                                            Wrappers.lambdaQuery(ProgramTeachPlan.class)
                                                    .eq(ProgramTeachPlan::getProgramId, trainingProgram.getId())
                                                    .eq(ProgramTeachPlan::getIsEnable, 1)
                                    ).stream()
                                    .flatMap(plan -> plan.getSemester().stream()
                                            .map(semester -> new AbstractMap.SimpleEntry<>(semester, plan.getCredit())))
                                    .collect(Collectors.groupingBy(
                                            AbstractMap.SimpleEntry::getKey,
                                            Collectors.summingDouble(Map.Entry::getValue)
                                    ))
                    );
                });


        return StuCreditRo.builder()
                .xAxis(semesterEnumList.stream()
                        .map(SemesterEnum::getSemester)
                        .collect(Collectors.toList())
                )
                .schemeCredits(semesterEnumList.stream()
                        .map(e -> {
                            Map<Integer, Double> integerDoubleMap = teachPlanMap.get();
                            if (CollUtil.isEmpty(integerDoubleMap)) {
                                return 0.0;
                            }
                            return ObjectUtil.isNotNull(integerDoubleMap.get(e.getSemesterId())) ? integerDoubleMap.get(e.getSemesterId()) : 0.0;
                        })
                        .collect(Collectors.toList())
                )
                .completedCredits(
                        semesterEnumList.stream()
                                .map(e -> ObjectUtil.isNotNull(stuScoreMap.get(e.getSemester())) ? stuScoreMap.get(e.getSemester()) : 0.0)
                                .collect(Collectors.toList())
                )
                .averageValue(
                        semesterEnumList.stream()
                                .map(e -> {
                                    Map<Integer, Double> integerDoubleMap = teachPlanMap.get();
                                    double teachPlan = CollUtil.isEmpty(integerDoubleMap) ? 0.0 : ObjectUtil.isNotNull(integerDoubleMap.get(e.getSemesterId())) ? integerDoubleMap.get(e.getSemesterId()) : 0.0;
                                    double score = ObjectUtil.isNotNull(stuScoreMap.get(e.getSemester())) ? stuScoreMap.get(e.getSemester()) : 0.0;
                                    return (teachPlan + score) / 2;
                                })
                                .collect(Collectors.toList())
                )
                .compulsoryCredits(
                        studentScoreList.stream()
                                .filter(s -> StudyRequireEnum.COMPULSORY.getCode().equals(s.getStudyRequire()))
                                .filter(s -> s.getScore() >= 60)
                                .mapToDouble(StudentScore::getCredits)
                                .filter(Objects::nonNull)
                                .sum()
                )
                .electiveCredits(
                        studentScoreList.stream()
                                .filter(s -> StudyRequireEnum.SELECT_EMBELLISH.getCode().equals(s.getStudyRequire()))
                                .filter(s -> s.getScore() >= 60)
                                .mapToDouble(StudentScore::getCredits)
                                .filter(Objects::nonNull)
                                .sum()
                )
                .build();
    }

    /**
     * 查询学生每学期学分绩点修读情况
     * @return
     */
    @Override
    public StuCreditRo statisticsStuGradePoint() {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (ObjectUtil.isEmpty(loginUser)) {
            throw new ServiceException("当前用户不存在，无法统计学生每学期学分修读情况！");
        }
        StudentInfo studentInfo = studentInfoService.getOne(Wrappers.lambdaQuery(StudentInfo.class).eq(StudentInfo::getUserId, loginUser.getUserId()));
        // 查询学生成绩信息
        List<StudentScore> studentScoreList = studentScoreService.list(
                Wrappers.lambdaQuery(StudentScore.class)
                        .eq(StudentScore::getUserId, loginUser.getUserId())
        );
        Map<String, Double> stuScoreMap = studentScoreList.stream()
                .collect(Collectors.toMap(
                        StudentScore::getSemester,
                        score -> score.getCredits() != null ? score.getCredits() * score.getGradePoint() : 0.0,
                        Double::sum
                ));
        // 按学制判断学期数
        List<SemesterEnum> semesterEnumList = SemesterEnum.getSemesterEnumList(studentInfo.getEducationalSystem());
        // 查询这个学生下的人才培养方案
        TrainingProgram trainingProgram = trainingProgramService.getOne(
                Wrappers.lambdaQuery(TrainingProgram.class)
                        .eq(TrainingProgram::getDepId, studentInfo.getDepId())
                        .eq(TrainingProgram::getSubjectId, studentInfo.getSubjectId())
                        .eq(TrainingProgram::getGrade, studentInfo.getGrade())
                        .eq(TrainingProgram::getIsEnable, 1)
        );
        AtomicReference<Map<Integer, Double>> teachPlanMap = new AtomicReference<>(Collections.emptyMap());
        Optional.ofNullable(trainingProgram)
                .ifPresent(t -> {
                    // 查询人才培养方案下的教学计划
                    teachPlanMap.set(
                            programTeachPlanService.list(
                                            Wrappers.lambdaQuery(ProgramTeachPlan.class)
                                                    .eq(ProgramTeachPlan::getProgramId, trainingProgram.getId())
                                                    .eq(ProgramTeachPlan::getIsEnable, 1)
                                    ).stream()
                                    .flatMap(plan -> plan.getSemester().stream()
                                            .map(semester -> new AbstractMap.SimpleEntry<>(semester, plan.getCredit() * 5)))
                                    .collect(Collectors.groupingBy(
                                            AbstractMap.SimpleEntry::getKey,
                                            Collectors.summingDouble(Map.Entry::getValue)
                                    ))
                    );
                });


        return StuCreditRo.builder()
                .xAxis(semesterEnumList.stream()
                        .map(SemesterEnum::getSemester)
                        .collect(Collectors.toList())
                )
                .schemeCredits(semesterEnumList.stream()
                        .map(e -> {
                            Map<Integer, Double> integerDoubleMap = teachPlanMap.get();
                            if (CollUtil.isEmpty(integerDoubleMap)) {
                                return 0.0;
                            }
                            return ObjectUtil.isNotNull(integerDoubleMap.get(e.getSemesterId())) ? integerDoubleMap.get(e.getSemesterId()) : 0.0;
                        })
                        .collect(Collectors.toList())
                )
                .completedCredits(
                        semesterEnumList.stream()
                                .map(e -> ObjectUtil.isNotNull(stuScoreMap.get(e.getSemester())) ? stuScoreMap.get(e.getSemester()) : 0.0)
                                .collect(Collectors.toList())
                )
                .averageValue(
                        semesterEnumList.stream()
                                .map(e -> {
                                    Map<Integer, Double> integerDoubleMap = teachPlanMap.get();
                                    double teachPlan = CollUtil.isEmpty(integerDoubleMap) ? 0.0 : ObjectUtil.isNotNull(integerDoubleMap.get(e.getSemesterId())) ? integerDoubleMap.get(e.getSemesterId()) : 0.0;
                                    double score = ObjectUtil.isNotNull(stuScoreMap.get(e.getSemester())) ? stuScoreMap.get(e.getSemester()) : 0.0;
                                    return (teachPlan + score) / 2;
                                })
                                .collect(Collectors.toList())
                )
                .compulsoryCredits(
                        studentScoreList.stream()
                                .filter(s -> StudyRequireEnum.COMPULSORY.getCode().equals(s.getStudyRequire()))
                                .filter(s -> s.getScore() >= 60)
                                .mapToDouble(m -> m.getCredits() * m.getGradePoint())
                                .filter(Objects::nonNull)
                                .sum()
                )
                .electiveCredits(
                        studentScoreList.stream()
                                .filter(s -> StudyRequireEnum.SELECT_EMBELLISH.getCode().equals(s.getStudyRequire()))
                                .filter(s -> s.getScore() >= 60)
                                .mapToDouble(m -> m.getCredits() * m.getGradePoint())
                                .filter(Objects::nonNull)
                                .sum()
                )
                .build();
    }
}
